/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package centerberg.engine;

import java.util.Arrays;

/**
 * A class representing a numerical vector in n-dimension.
 * Should not be confused with java.util.Vector
 * 
 * @author Andreas Svanberg
 */
public class Vector
{
    private double[] numbers;
    
    /**
     * Creates a new vector.
     * 
     * @param nums the numbers.
     */
    public Vector(double... nums)
    {
        if (nums.length < 1)
            throw new IllegalArgumentException("No 0-dimensional vectors");
        
        numbers = nums;
    }
    
    /**
     * Creates a new vector which is a copy of the specified vector.
     * 
     * @param v the vector to make a copy of
     */
    public Vector(Vector v)
    {
        numbers = (double[])Arrays.copyOf(v.numbers, v.numbers.length);
    }
    
    /**
     * Adds two vectors and returns the result. This vector remains unchanged.
     * 
     * @param vector the vector to add
     * @return       the sum of the two vectors
     */
    public Vector add(Vector vector)
    {
        if (vector.size() != size())
            throw new IllegalArgumentException("Vector must be of the same dimension");
        
        Vector v = new Vector(this);
        for (int index = 0; index < size(); index++)
            v.numbers[index] += vector.numbers[index];
        
        return v;
    }
    
    /**
     * Scalar division. This vector remains unchade.
     * 
     * @param num the number to divide by
     * @return    the new vector
     */
    public Vector divide(double num)
    {
        Vector v = new Vector(this);
        for (int index = 0; index < size(); index++)
            v.numbers[index] /= num;
        return v;
    }
    
    /**
     * Returns the dot-product of two vectors.
     * 
     * @param v1
     * @param v2
     * @return   the dot product of the two vectors
     */
    public static double dot(Vector v1, Vector v2)
    {
        if (v1.size() != v2.size())
            throw new IllegalArgumentException("Vectors must be of the same dimension");
        
        double n = 0;
        for (int index = 0; index < v1.size(); index++)
            n += v1.numbers[index] * v2.numbers[index];
        return n;
    }
    
    /**
     * Convenience method to return the first number in this vector.
     * 
     * @return the first (x) number in the vector
     */
    public double getX()
    {
        return numbers[0];
    }
    
    /**
     * Convenience method to return the second number in this vector.
     * 
     * @return the second (y) number in the vector
     */
    public double getY()
    {
        return numbers[1];
    }
    
    /**
     * Scalar multiplication. This vector remains unchanged.
     * 
     * @param num the number to multiply with
     * @return    the new vector
     */
    public Vector multiply(double num)
    {
        Vector v = new Vector(this);
        for (int index = 0; index < size(); index++)
            v.numbers[index] *= num;
        return v;
    }
    
    /**
     * Sets the number at the given index to the specified value.
     * 
     * @param index the index to change
     * @param value the new number
     */
    public void set(int index, double value)
    {
        numbers[index] = value;
    }
    
    /**
     * Returns the number of elements in this vector.
     * 
     * @return the number of elements
     */
    public int size()
    {
        return numbers.length;
    }
    
    /**
     * Subtracts two vectors and returns the result. This vector remains unchanged.
     * 
     * @param vector the vector to subtract
     * @return       the result
     */
    public Vector subtract(Vector vector)
    {
        if (vector.size() != size())
            throw new IllegalArgumentException("Vectors must be of the same dimension");
        
        Vector v = new Vector(this);
        for (int index = 0; index < size(); index++)
            v.numbers[index] -= vector.numbers[index];
        return v;
    }
    
    /**
     * Returns the magnitude of this vector.
     * 
     * @return the magnitude
     */
    public double length()
    {
        double length = 0;
        for (int index = 0; index < size(); index++)
            length += numbers[index] * numbers[index];
        return Math.sqrt(length);
    }
    
    /**
     * Normalizes the vector (sets magnitude to 1).
     */
    public void normalize()
    {
        double length = length();
        for (int index = 0; index < size(); index++)
            numbers[index] /= length;
    }
    
    /**
     * Returns a textual visualisation of this vector.
     * 
     * @return the vector in text-form
     */
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        sb.append('(').append(numbers[0]);
        for (int index = 1; index < size(); index++)
            sb.append(", ").append(numbers[index]);
        sb.append(')');
        return sb.toString();
    }
}
